from PIL import Image,ImageFont,ImageDraw,ImageFilter
                # 画布,  画笔,        画线,      模糊
import os  # 拼接路径
import string # 生成26个字母的大小写与0-9的数字
import random # 随机生成
import io # 文件流模块
# 校验码
class CheckCode:
    def __init__(self,width=150,height=40,length=4,size=25):
        '''
         初始化
        :param width: 图片的宽度
        :param height: 图片的长度
        :param length: 图片的字符长度
        :param size: 图片的字符的大小
        '''
        self.width = width
        self.height = height
        self.length = length
        self.size = size

    def random_str(self):
        '''
        随机字符串
        随机生成26个大小写字母与10个数字
        :return:
        '''
        random_char = string.ascii_letters + string.digits  # 把26个字母的大小写与0-9的数字拼接在一起
        # 返回随机生成的字符串
        return ''.join(random.sample(random_char,self.length))  # 第一个:随机的元素,第二个:随机的数量 返回的是一个list类型的数据 通过join方法转成字符串


    def random_color(self,stan=0,end=255):
        '''
        随机颜色RGB
        :param stan: 起始值
        :param end: 结束值
        :return: tuple(r,g,b)  # 返回三个数值以元组的形式
        '''
        value = (random.randint(stan,end) for i in range(3))  # 循环随机生成三个数值
        return tuple(value)  # 注意返回必须是一个元组的形式返回



    def random_lied(self,dr):
        '''
        绘制干扰线
        一条线是由俩个点绝定的分别是(x,y)

        :param dr:画笔对象
        :return:
        '''
        for o in range(self.length): # 确定画几条线
            # self.width随机他的宽度x轴点
            # self.height随机他的高度y轴点
            lines = [(random.randint(0,self.width),random.randint(0,self.height)) for n in range(2)]  # 这循环2次不是8条线了吗？？

            # 使用画笔对象调用line方法画线
            # 用画笔将随机的俩点用fill颜色连成一条3ps的线
            dr.line(list(lines),fill=self.random_color(stan=120),width=3)  # fill 画笔的颜色,width控制线的宽度,stan=控制线的颜色的浅度


    def random_poins(self,dr,rate):
        '''
        绘制干扰点
        :param dr: 画笔对象
        :param rate: 出现点的频率
        :return:
        '''
        for x in range(self.width): # x轴取值
            for y in range(self.height): # y轴取值
                # 循环随机得到的值小于或者等于传过来的频率值则进行画点的操作
                if random.randint(1,100) <= rate:  # 控制画点出现的频率,满足条件则画点
                    # 画笔对象 调用point方法画点
                    dr.point((x,y),fill=self.random_color()) # 循环的x轴值于y轴值 fill 随机的颜色






    def img_code(self):
        '''
        生成验证码图片
        :return:
        '''
        # 创建画布,创建Image对象,调用new方法 255 表示白色的
        res = Image.new('RGB',(self.width,self.height),(255,255,255)) # 第一个:创建图片的格式以RGB格式创建,第二个:图片的宽度与长度,第三个:图片的背景颜色数字

        # 创建字体对象,创建ImageFont对象.调用truetype方法
        # 路径
        absolute = os.path.dirname(os.path.abspath(__file__))  # 表示当前py文件下的绝对路径  /home/bd/CMR/lms/uitl/verifyutil.py
        # 通过os.path.dirname 获取文件名 /home/bd/CMR/lms/uitl

        font = ImageFont.truetype( f'{absolute}'+'/HYYakuHei-85W.ttf',self.size) # 第一个:画笔的文件路径,第二个:字体大小

        # 创建画笔,创建ImageDraw对象,调用Draw方法
        dr = ImageDraw.Draw(res) # 传入画布对象

        # 随机生成字母与数字
        cone = self.random_str()

        # 将返回的字符串画上画布当中
        for i in range(self.length):
            # 将返回的字符串以(30 * i,3)的坐标处开始,cone取元素,用font画笔,用fill颜色
                            # x轴   y轴
                    # 第一个:坐标系,第二个:取出随机生成的字符串元素,第三个:画笔对象的使用,第四个:随机生成字体颜色
            dr.text((30 * i +20,3),cone[i],font=font,fill=self.random_color(stan=0,end=60))  # end表示颜色深度在150以内


        # 绘制干扰线
        self.random_lied(dr) # 传入画笔对象

        # 绘制干扰点
        self.random_poins(dr,15) # 传入画笔对象

        # 绘制模糊
        res = res.filter(ImageFilter.BLUR)

        return res,cone # 返回画布,随机的验证码




if __name__ == '__main__':
    ima = CheckCode()
    canvas = ima.img_code()

    with open('tes.png','wb') as f:  # 以文本的形式保留 以wb二进制写入进去
        canvas.save(f)  # 把返回的画布保存到文本里面去


